package com.yuanchu.common.exception;

import com.yuanchu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

/**
 * @version: 1.0
 * @Author: adan
 * @description: 全局异常处理
 * @date: 2023-12-20 0:14
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理请求参数校验异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        // 打印详细信息
        logError(request,e);
        log.error("数据校验出现问题{},异常类型{}", e.getMessage(), e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        HashMap<String, String> map = new HashMap<>();
        String defaultMessage = bindingResult.getFieldErrors().get(0).getDefaultMessage();
        bindingResult.getFieldErrors().forEach(item -> {
            String message = item.getDefaultMessage();
            String field = item.getField();
            map.put(field, message);
        });

        return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), defaultMessage)
                .put("data", map);
    }

    @ExceptionHandler(value = AccessDeniedException.class)
    public R handleAccessDeniedException(HttpServletRequest request, AccessDeniedException e) {
        // 打印详细信息
        logError(request,e);
        log.error("不允许访问{},异常类型{}", e.getMessage(), e.getClass());
        return R.error(BizCodeEnum.ACCESS_DENIED.getCode(), BizCodeEnum.ACCESS_DENIED.getMsg());
    }

    @ExceptionHandler(value = SocketTimeoutException.class)
    public R handleSocketTimeoutException(HttpServletRequest request, AccessDeniedException e) {
        // 打印详细信息
        // logError(request,e);
        log.error("请求超时：{}", e.getMessage());
        return R.error(BizCodeEnum.TIME_OUT.getCode(), BizCodeEnum.TIME_OUT.getMsg());
    }

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(value = YuanChuException.class)
    public R handleRRException(YuanChuException e) {
        log.error("YuanChuException异常，异常类型{};异常信息{}", e.getMsg(),e.getClass());
        return R.ok(e.getCode(), e.getMsg());
    }
    /**
     * 处理自定义异常
     */
    @ExceptionHandler(value = OrderException.class)
    public R handleOrderxception(OrderException e) {
        Map<String, Object> map = new HashMap<>();
        map.put("is_created", false);
        log.error("OrderException异常, 异常信息{}", e.getMsg());
        return R.ok(e.getCode(), e.getMsg()).put("data", map);
    }


    /**
     * 处理全局异常
     */
    @ExceptionHandler(value = Exception.class)
    public R handleException(HttpServletRequest request, Exception e) {
        logError(request,e);
        log.error("未知异常，异常类型{}", e.getClass());
        return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMsg());
    }

    public void logError(HttpServletRequest request, Exception exception) {
        //换行符
        String lineSeparatorStr = System.getProperty("line.separator");

        StringBuilder exStr = new StringBuilder();
        StackTraceElement[] trace = exception.getStackTrace();
        // 获取堆栈信息并输出为打印的形式
        for (StackTraceElement s : trace) {
            exStr.append("\tat " + s + "\r\n");
        }
        //打印error级别的堆栈日志
        log.error("访问地址：" + request.getRequestURL() + ",请求方法：" + request.getMethod() +
                ",远程地址：" + request.getRemoteAddr() + lineSeparatorStr +
                "错误堆栈信息如下:" + exception.toString() + lineSeparatorStr + exStr);
    }



}
